﻿using Microsoft.Extensions.Caching.Distributed;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

namespace KAsFrame.Common.Extensions
{
    public static class DistributedCacheExtensions
    {
        public static T Get<T>(this IDistributedCache source, string key) where T : class
        {
            var value = source.GetString(key);
            if (string.IsNullOrEmpty(value)) return default;
            return JsonSerializer.Deserialize<T>(value);
        }
        public static async Task<T> GetAsync<T>(this IDistributedCache source, string key) where T : class
        {
            var value = await source.GetStringAsync(key);
            if (string.IsNullOrEmpty(value)) return default;
            return JsonSerializer.Deserialize<T>(value);
        }

        public static async Task<T> GetValueAsync<T>(this IDistributedCache source, string key) where T : struct
        {
            object result = default(T);
            var value = await source.GetStringAsync(key);
            if (string.IsNullOrEmpty(value)) return default;
            var typeCode = Type.GetTypeCode(typeof(T));
            switch (typeCode)
            {
                case TypeCode.Boolean:
                    {
                        if (bool.TryParse(value, out bool _value))
                            result = _value;
                    }
                    break;
                case TypeCode.DateTime:
                    {
                        if (DateTime.TryParse(value, out DateTime _value))
                            result = _value;
                    }
                    break;
                case TypeCode.Int32:
                    {
                        if (int.TryParse(value, out int _value))
                            result = _value;
                    }
                    break;
                case TypeCode.Decimal:
                    {
                        if (decimal.TryParse(value, out decimal _value))
                            result = _value;
                    }
                    break;
                case TypeCode.Double:
                    {
                        if (double.TryParse(value, out double _value))
                            result = _value;
                    }
                    break;
                case TypeCode.Int64:
                    {
                        if (long.TryParse(value, out long _value))
                            result = _value;
                    }
                    break;
                default:
                    break;
            }
            return (T)result;
        }

        public static void Cache(this IDistributedCache source, string key, object obj, DistributedCacheEntryOptions options = null)
        {
            if (options == null)
                source.SetString(key, JsonSerializer.Serialize(obj));
            else
                source.SetString(key, JsonSerializer.Serialize(obj), options);
        }
        public static void Cache(this IDistributedCache source, string key, object obj, double seconds)
        {
            source.SetString(
                   key, JsonSerializer.Serialize(obj),
                   new DistributedCacheEntryOptions().SetSlidingExpiration(TimeSpan.FromSeconds(seconds))
               );
        }

        public static async Task CacheAsync(this IDistributedCache source, string key, object obj, DistributedCacheEntryOptions options = null)
        {
            if (options == null)
                await source.SetStringAsync(key, JsonSerializer.Serialize(obj));
            else
                await source.SetStringAsync(key, JsonSerializer.Serialize(obj), options);
        }
        public static async Task CacheAsync(this IDistributedCache source, string key, object obj, double seconds)
        {
            await source.SetStringAsync(
                    key, JsonSerializer.Serialize(obj),
                    new DistributedCacheEntryOptions().SetSlidingExpiration(TimeSpan.FromSeconds(seconds))
                );
        }

        public static void CacheLongTerm(this IDistributedCache source, string key, object obj)
        {
            var options = new DistributedCacheEntryOptions().SetSlidingExpiration(TimeSpan.FromSeconds(30 * 24 * 3600));
            source.Cache(key, obj, options);
        }
        public static async Task CacheLongTermAsync(this IDistributedCache source, string key, object obj)
        {
            var options = new DistributedCacheEntryOptions().SetSlidingExpiration(TimeSpan.FromSeconds(30 * 24 * 3600));
            await source.CacheAsync(key, obj, options);
        }

        public static void Remove(this IDistributedCache cache, params string[] arrKey)
        {
            foreach (var key in arrKey)
            {
                cache.Remove(key);
            }
        }

        public static Task RemoveAsync(this IDistributedCache cache, params string[] arrKey)
        {
            return Task.Run(() =>
                {
                    foreach (var key in arrKey)
                    {
                        cache.RemoveAsync(key);
                    }
                }
            );
        }
    }
}
